#!/usr/bin env python
# -*- coding: utf-8 -*-
###########################################################################
#   Copyright (C) 2008 by Serj Poltavsky                                  #
#   serge.uliss at gmail.com                                              #
#                                                                         #
#   This program is free software; you can redistribute it and/or modify  #
#   it under the terms of the GNU General Public License as published by  #
#   the Free Software Foundation; either version 3 of the License, or     #
#   (at your option) any later version.                                   #
#                                                                         #
#   This program is distributed in the hope that it will be useful,       #
#   but WITHOUT ANY WARRANTY; without even the implied warranty of        #
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
#   GNU General Public License for more details.                          #
#                                                                         #
#   You should have received a copy of the GNU General Public License     #
#   along with this program. If not, see <http://www.gnu.org/licenses/>   #
###########################################################################

import os
import sys
import select
import subprocess
from PIL import Image, ImageDraw

from convert import Convert

class ColorImage:
    def __init__(self, color, size):
        self.color = color
        self.size = size

    def save(self, filename, format):
        if __debug__:
            print >>sys.stderr, "Generating color image (0x%06x)..." % self.color

        red =  (self.color & 0xFF0000) >> 16
        green = (self.color & 0x00FF00) >> 8
        blue = self.color & 0x0000FF
        image = Image.new("RGB", self.size, (red,green,blue))
        image.save(filename, format)

class ImageCombine(object):
    PALETTE = [
        0,   0,   0,  # black,  00
        0,   255, 0,  # green,  01
        255, 0,   0,  # red,    10
        255, 255, 0,  # yellow, 11
        ] + [0, ] * 252 * 3

    def __init__(self, size, filename=None, indexed=False):
        self.size = size
        self.filename = filename
        self.indexed = indexed
        self.palette = self.PALETTE
        self.__files = []
        self.init_img()

    def add(self, image, pos = (0, 0)):
        self.__files.append((image, pos))

    def apply_pallette(self):
        pal_image = Image.new("P", (1,1))
        pal_image.putpalette(self.palette)
        self.image = self.image.convert("RGB").quantize(palette=pal_image)
        self.image = self.image.convert("P")

    def combine(self):
        for im_file, pos in self.__files:
            im = Image.open(im_file)
            self.image.paste(im, pos, im.convert("RGBA"))

    def init_img(self):
        if self.filename is None:
            self.image = Image.new('RGBA', self.size)
        else:
            self.image = Image.open(self.filename)

    def check_colors(self):
        return self.image.getcolors(4) is not None

    def save(self, filename):
        self.combine()
        if self.indexed and self.check_colors():
            self.apply_pallette()
            self.image.save(filename, "PNG",transparency=0)
        else:
            self.image.save(filename, "PNG")

class ImageConvert(Convert):
    formats_map = {
        'png' : 'png2yuv',
        'jpg' : 'jpeg2yuv',
        'gif' : 'gif2yuv'
        }

    video_format_frate = {
        'pal' :  ('-f', '25'),
        'ntsc' : ('-f', '29.97')
    }

    __frames_to_gen = 25

    def __init__(self, src, dest, video_format):
        Convert.__init__(self, src, dest)
        self.video_format = video_format

    def __progress(self, stream):
        while True:
            data = select.select([stream.fileno()],[],[])
            ln = stream.readline()
            if ln == '':
                # EOF
                self.progress_hook(100)
                break
            #INFO: [mpeg2enc] Frame    46    46 P q=8.00 sum act=3336.78206
            if ln.find('[mpeg2enc] Frame') != -1 and ln.find('rate') == -1:
                frame = int(ln.split()[3])
                percent = int(frame*100.0/self.__frames_to_gen)
                self.progress_hook(percent)

    def convert(self):
        cmd0, cmd1 = self.make_cmds()

        if not self.is_src_exists():
            raise RuntimeError('Source file not exists: %s' % self.src)
        if __debug__:
            print >>sys.stderr, "Converting image '%s'" % os.path.basename(self.src)
        p1 = subprocess.Popen(cmd0, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        p2 = subprocess.Popen(cmd1, stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        self.__progress(p2.stderr)
        p2.communicate()
        if p2.returncode != 0:
            print >>sys.stderr, "Error while converting image"
            return False
        return True

    def format(self):
        if self.src is None:
            return None
        pos = self.src.rfind('.')
        if pos == -1:
            return None
        ext = self.src[pos+1:].lower()
        return ext if ext in('png', 'jpg', 'gif') else None

    def get_video_format(self):
        return self.__video_format

    def make_convert2yum_cmd(self):
        prog_name = self.formats_map.get(self.format())
        if prog_name is None:
            raise RuntimeError('Command not found')
        cmd = [prog_name]
        cmd.extend(("-n", str(self.__frames_to_gen), "-I", "p"))
        cmd.extend(self.video_format_frate[self.video_format])
        cmd.extend(("-j", self.src))
        return cmd

    def make_mpeg_cmd(self):
        cmd = ["mpeg2enc", "-f", "8", "-o"]
        # PAL/NTSC
        if self.video_format == 'ntsc':
            cmd.extend(['-F', '4'])
        cmd.append(str(self.dest))
        return cmd

    def make_cmds(self):
        format = self.format()
        if format is None:
            raise RuntimeError('Unknown source file format')

        cmd0 = self.make_convert2yum_cmd()
        cmd1 = self.make_mpeg_cmd()

        if __debug__:
            print >>sys.stderr, " ".join(cmd0), '|', " ".join(cmd1)
        return (cmd0, cmd1)

    def set_video_format(self, fmt):
        if fmt.lower() in ('pal', 'ntsc'):
            self.__video_format = fmt.lower()
        else:
            raise ValueError('Wrong video format: %s' % fmt)

    video_format = property(get_video_format, set_video_format)